package com.dwxt.cdms.util;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

/**
 * @author yql
 * @version 1.0
 * @date 2020/12/8 下午2:49
 */
public class SecretUtil {

    private static Logger logger = LoggerFactory.getLogger(RsaUtil.class);

    public static final Integer KEY_TYPE_LOGIN = 1;

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;
    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 256;

    public static String encode(String message)  {
        // TODO 文件存在性校验
        String messageEncode = null;
        try {
            // 加载私钥文件地址
            String classFilePath = null;
            // 本地测试 文件路径
            classFilePath = "/app/city";
            String publicKeyStr = loadPublicKeyByFile(classFilePath);
            RSAPublicKey publicKey = loadPublicKeyByStr(publicKeyStr);
            // 公钥加密
            byte[] res = RsaEncrypt.encrypt(publicKey,message.getBytes("utf-8"));
            // base64编码
            byte[] decodeBase64 = Base64.encodeBase64(res);
            if(null == decodeBase64){
                return null;
            }
            messageEncode = new String(decodeBase64,"utf-8");
        }catch (Exception ex){
            logger.error("RSAUtil.encode error" + ex.getMessage());
        }
        return messageEncode;
    }

    /**
     * 从文件中输入流中加载公钥
     *
     * @throws Exception
     *             加载公钥时产生的异常
     */
    public static String loadPublicKeyByFile(String path) throws Exception {
        try {
            BufferedReader br = new BufferedReader(new FileReader(path
                    + "/publicKey.keystore"));
            String readLine = null;
            StringBuilder sb = new StringBuilder();
            while ((readLine = br.readLine()) != null) {
                sb.append(readLine);
            }
            br.close();
            return sb.toString();
        } catch (IOException e) {
            throw new Exception("公钥数据流读取错误");
        } catch (NullPointerException e) {
            throw new Exception("公钥输入流为空");
        }
    }

    /**
     * 从字符串中加载公钥
     *
     * @param publicKeyStr
     *            公钥数据字符串
     * @throws Exception
     *             加载公钥时产生的异常
     */
    public static RSAPublicKey loadPublicKeyByStr(String publicKeyStr)
            throws Exception {
        try {
            byte[] buffer = Base64.decodeBase64(publicKeyStr);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此算法");
        } catch (InvalidKeySpecException e) {
            throw new Exception("公钥非法");
        } catch (NullPointerException e) {
            throw new Exception("公钥数据为空");
        }
    }

    /**
     * 公钥加密过程
     *
     * @param publicKey
     *            公钥
     * @param plainTextData
     *            明文数据
     * @return
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData)
            throws Exception {
        if (publicKey == null) {
            throw new Exception("加密公钥为空, 请设置");
        }
        Cipher cipher = null;
        try {
            // 使用默认RSA
            cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            //长度
            final int len = plainTextData.length;
            //偏移量
            int offset = 0;
            //段数
            int i = 0;
            final ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while (len > offset) {
                byte[] cache;
                if (len - offset > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(plainTextData, offset, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(plainTextData, offset, len - offset);
                }
                bos.write(cache);
                i++;
                offset = MAX_ENCRYPT_BLOCK * i;
            }
            byte[] output = bos.toByteArray();
            bos.close();
            return output;
        } catch (NoSuchAlgorithmException e) {
            throw new Exception("无此加密算法");
        } catch (NoSuchPaddingException e) {
            logger.error(e.getMessage());
            return null;
        } catch (InvalidKeyException e) {
            throw new Exception("加密公钥非法,请检查");
        } catch (IllegalBlockSizeException e) {
            throw new Exception("明文长度非法");
        } catch (BadPaddingException e) {
            throw new Exception("明文数据已损坏");
        }
    }

    public static String decode(String encodeStr,Integer keyType){
        // TODO 文件存在性校验
        String passwordDecode = null;
        String classFilePath = null;
        String privateKeyStr = null;
        try {
            // 本地文件位置
            classFilePath = " ";
            privateKeyStr = RsaEncrypt.loadPrivateKeyByFile(classFilePath);
            RSAPrivateKey privateKey = RsaEncrypt.loadPrivateKeyByStr(privateKeyStr);
            // base64解码
            byte[] decodeBase64 = Base64.decodeBase64(encodeStr);
            // 私钥解密
            byte[] res = RsaEncrypt.decrypt(privateKey,decodeBase64);
            passwordDecode = new String(res,"utf-8");
        }catch (Exception ex){

        }
        return passwordDecode;
    }


    //实例流程
    public static void main(String[] args) {
    	//appSecretStr换成自己的
        String pass = "appSecretStr";
        pass = MD5Util.MD5EncodeUtf8(pass);
        System.out.println("pass:"+pass);
        pass = MD5Util.MD5EncodeUtf8(pass+"nb_lbhf");
        System.out.println("pass:"+pass);
        String a = encode(pass);
        //最终值
        System.out.println(a);
    }

}
